import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import warnings
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import geopandas as gpd
from urllib.request import urlopen
from numpy import mean
import folium
warnings.filterwarnings('ignore')
Precio del combustible en Colombia durante el 2023#
data1 = pd.read_csv("precios.csv")
data2 = pd.read_csv("precios (1).csv")
data3 = pd.read_csv("precios (2).csv")
data4 = pd.read_csv("precios (3).csv")
data = pd.concat([data1, data2, data3, data4], ignore_index=True)
display(data.head(10).style.set_caption("Base de datos: Precio del combustible en Colombia durante el 2023"))
| BANDERA | NOMBRE COMERCIAL | PRODUCTO | FECHA REGISTRO | DEPARTAMENTO | MUNICIPIO | VALOR PRECIO | |
|---|---|---|---|---|---|---|---|
| 0 | TERPEL | ESTACION DE SERVICIO SERVICENTRO LA PEDRERA | DIESEL | 01-Jan-2023 | AMAZONAS | LA PEDRERA | 15000.000000 |
| 1 | TERPEL | ESTACION DE SERVICIO SERVICENTRO LA PEDRERA | GASOLINA MOTOR | 01-Jan-2023 | AMAZONAS | LA PEDRERA | 15500.000000 |
| 2 | TERPEL | BALSA EL CONDOR | GASOLINA MOTOR | 01-Jan-2023 | AMAZONAS | LETICIA | 11380.000000 |
| 3 | TERPEL | BALSA EL CONDOR | DIESEL | 01-Jan-2023 | AMAZONAS | LETICIA | 10840.000000 |
| 4 | TERPEL | ESTACION DE SERVICIO DISTRIBUIDORA LOS COMUNEROS | GASOLINA MOTOR | 01-Jan-2023 | AMAZONAS | LETICIA | 11380.000000 |
| 5 | TERPEL | ESTACION DE SERVICIO DISTRIBUIDORA LOS COMUNEROS | GASOLINA MOTOR | 01-Jan-2023 | AMAZONAS | LETICIA | 11380.000000 |
| 6 | TERPEL | ESTACION DE SERVICIO DISTRIBUIDORA LOS COMUNEROS | DIESEL | 01-Jan-2023 | AMAZONAS | LETICIA | 10671.000000 |
| 7 | TEXACO | EDS COMDECOM ABRIAQUI | GASOLINA MOTOR | 01-Jan-2023 | ANTIOQUIA | ABRIAQUÍ | 11870.000000 |
| 8 | TEXACO | EDS COMDECOM ABRIAQUI | DIESEL | 01-Jan-2023 | ANTIOQUIA | ABRIAQUÍ | 10910.000000 |
| 9 | TEXACO | ESTACIÓN DE SERVICIO Y MALL SANTA LUCIA S.A.S. | DIESEL | 01-Jan-2023 | ANTIOQUIA | AMAGÁ | 9610.000000 |
print(data.shape)
(268001, 7)
La base de datos ‘data’ contiene 268,001 observaciones distribuidas en 7 variables. A continuación, se presentan los nombres de las variables:
print(data.columns)
Index(['BANDERA', 'NOMBRE COMERCIAL', 'PRODUCTO', 'FECHA REGISTRO',
'DEPARTAMENTO', 'MUNICIPIO', 'VALOR PRECIO'],
dtype='object')
Análisis de Variables#
Variable Categórica#
Tabla de frecuencia variable ‘BANDERA’
conteo_banderas = data['BANDERA'].value_counts().reset_index()
conteo_banderas.columns = ['Bandera', 'Frecuencia']
print(conteo_banderas)
Bandera Frecuencia
0 TERPEL 94823
1 PRIMAX 36112
2 BIOMAX 32225
3 TEXACO 27092
4 PETROMIL 17249
5 COOMULPINORT 8918
6 AYATAWACOOP 8078
7 ZEUSS 7488
8 PETROBRAS 4871
9 DISCOWACOOP 3929
10 ECOS 3613
11 ESSO 3502
12 PETRDECOL 3495
13 PETRODECOL 3337
14 PUMA 3059
15 DISCOM 2917
16 OCTANO 2221
17 PLUS MAS 1806
18 P Y B 1687
19 BRIO 719
20 ZAPATA Y VELASQUEZ 408
21 SAVE 285
22 PROXXON 167
Tabla de frecuencia variable ‘DEPARTAMENTO’
conteo_departamentos = data['DEPARTAMENTO'].value_counts().reset_index()
conteo_departamentos.columns = ['Departamento', 'Frecuencia']
print(conteo_departamentos)
Departamento Frecuencia
0 NARIÑO 31054
1 ANTIOQUIA 25009
2 NORTE DE SANTANDER 21752
3 VALLE DEL CAUCA 18754
4 CUNDINAMARCA 16631
5 BOGOTA D.C. 16031
6 CESAR 15703
7 LA GUAJIRA 13694
8 SANTANDER 10247
9 ATLANTICO 8595
10 TOLIMA 8014
11 BOYACA 7769
12 CORDOBA 7440
13 BOLIVAR 7027
14 PUTUMAYO 6610
15 HUILA 6355
16 META 6250
17 CAUCA 5617
18 RISARALDA 5435
19 MAGDALENA 5339
20 CALDAS 4517
21 SUCRE 4358
22 CASANARE 2744
23 CHOCO 2640
24 QUINDIO 2555
25 CAQUETA 2390
26 ARAUCA 2312
27 GUAVIARE 1043
28 VICHADA 922
29 AMAZONAS 513
30 ARCHIPIELAGO DE SAN ANDRES, SANTA CATALINA Y P... 267
31 GUAINIA 261
32 VAUPES 153
Tabla de frecuencia variable ‘PRODUCTO’ y visualización de la distribución.
print(data['PRODUCTO'].value_counts().reset_index().rename(columns={'index': 'Producto', 'PRODUCTO': 'Frecuencia'}))
plt.figure(figsize=(10, 6))
sns.countplot(data=data, x='PRODUCTO', palette=['#0077b6', '#00b4d8', '#023e8a'])
plt.title('Distribución de combustible por producto')
plt.xlabel('PRODUCTO')
plt.ylabel('Frecuencia')
plt.xticks(rotation=45)
plt.show()
Frecuencia count
0 GASOLINA MOTOR 127338
1 DIESEL 108263
2 EXTRA 32400
Se nota que el combustible tipo Extra tiene una distribución considerablemente menor en comparación con la Gasolina Motor, que fue el combustible más vendido en Colombia durante el año 2023, con un total de 127.338 registros.
Variable Númerica#
print(data['VALOR PRECIO'].describe())
plt.figure(figsize=(10, 6))
plt.hist(data['VALOR PRECIO'].dropna(), bins=50, color='lightblue')
plt.title('Valor del combustible')
plt.xlabel('VALOR PRECIO')
plt.ylabel('Frecuencia')
plt.show()
count 2.680010e+05
mean 1.202214e+04
std 2.870676e+04
min 0.000000e+00
25% 9.350000e+03
50% 1.087000e+04
75% 1.384700e+04
max 1.475015e+07
Name: VALOR PRECIO, dtype: float64
Identificar datos faltantes#
## Identificar y manejar NA
print(data.isna().sum())
BANDERA 0
NOMBRE COMERCIAL 0
PRODUCTO 0
FECHA REGISTRO 0
DEPARTAMENTO 0
MUNICIPIO 0
VALOR PRECIO 0
dtype: int64
Detección de valores atípicos#
En el histograma de la variable numérica ‘VALOR PRECIO’ se observó una fuerte asimetría hacia la izquierda, indicando que la mayoría de los datos se encuentran concentrados en valores bajos. Además, se identificó un valor máximo significativamente mayor que el resto de los datos, lo que sugiere la presencia de valores atípicos o una cola larga en la distribución.
## Reemplazar valores atípicos
atipico = data['VALOR PRECIO'].quantile(0.98)
data.loc[data['VALOR PRECIO'] > atipico, 'VALOR PRECIO'] = pd.NA
median_value = data['VALOR PRECIO'].median()
data['VALOR PRECIO'].fillna(median_value, inplace=True)
plt.figure(figsize=(10, 6))
plt.boxplot(data['VALOR PRECIO'], patch_artist=True, boxprops=dict(facecolor='#6ab5b0'))
plt.title('Precio del combustible')
plt.ylabel('VALOR PRECIO')
plt.show()
print(data['VALOR PRECIO'].describe())
count 268001.000000
mean 11755.836161
std 3257.278929
min 0.000000
25% 9350.000000
50% 10760.000000
75% 13610.000000
max 20282.000000
Name: VALOR PRECIO, dtype: float64
Para manejar los valores atípicos en la variable numérica, primero identificamos aquellos valores que se encuentran significativamente por encima del rango típico de la distribución, utilizando el percentil 98 como umbral. Los valores superiores a este umbral fueron reemplazados por NA para mitigar el impacto de los valores atípicos en el análisis. Posteriormente, los valores faltantes (NA) fueron imputados con la mediana de los datos restantes, garantizando así una base de datos más uniforme para el análisis.
print(data['VALOR PRECIO'].describe())
plt.figure(figsize=(10, 6))
plt.hist(data['VALOR PRECIO'].dropna(), bins=50, color='lightblue')
plt.title('Valor del combustible')
plt.xlabel('VALOR PRECIO')
plt.ylabel('Frecuencia')
plt.show()
count 268001.000000
mean 11755.836161
std 3257.278929
min 0.000000
25% 9350.000000
50% 10760.000000
75% 13610.000000
max 20282.000000
Name: VALOR PRECIO, dtype: float64
Mapa de Colombia#
Mapa fijo#
Creamos una imagen representativa del mapa de colombia usando un archivo Shapefile
mapa = gpd.read_file("C:\\Users\\KELLY\\Documents\\MGN2023_DPTO_POLITICO (1)")
mapa['dpto_cnmbr'] = mapa['dpto_cnmbr'].replace({
"NARI?O" : "NARIÑO","BOGOTÁ, D.C.":"BOGOTA D.C.", "BOLÍVAR" :"BOLIVAR","BOYACÁ":"BOYACA", "ATLÁNTICO":"ATLANTICO","CAQUETÁ": "CAQUETA", "CHOCÓ":"CHOCO","GUAINÍA":"GUAINIA","CÓRDOBA":"CORDOBA", "VAUPÉS":"VAUPES"
})
data['DEPARTAMENTO'] = data['DEPARTAMENTO'].replace({
"ARCHIPIELAGO DE SAN ANDRES, SANTA CATALINA Y PROVIDENCIA": "ARCHIPIELAGO DE SAN ANDRES"
})
precios = data.groupby('DEPARTAMENTO')['VALOR PRECIO'].mean().reset_index()
precios.columns = ['DEPARTAMENTO', 'PROMEDIO']
mapa = mapa.rename(columns={'dpto_cnmbr': 'DEPARTAMENTO'})
mapa = mapa.merge(precios, on='DEPARTAMENTO')
norm = mcolors.Normalize(vmin=mapa['PROMEDIO'].min(), vmax=mapa['PROMEDIO'].max())
cmap = plt.get_cmap('plasma_r')
fig, ax = plt.subplots(1, 1, figsize=(14, 10))
mapa.plot(column='PROMEDIO', ax=ax, legend=True, cmap=cmap, norm=norm, edgecolor='black',
legend_kwds={'label': "Precio Promedio",
'orientation': "vertical"})
for x, y, label in zip(mapa.geometry.centroid.x, mapa.geometry.centroid.y, mapa['DEPARTAMENTO']):
ax.annotate(label, xy=(x, y), xytext=(-10, -5), textcoords='offset points', fontsize=7, color='Black')
plt.title('Precio Promedio por Departamento en Colombia')
plt.show()
Mapa interactivo#
Para hacer el mapa interactivo, se usó la biblioteca folium en lugar de matplotlib. folium permite crear mapas interactivos en los que puedes hacer zoom, mover el mapa, y agregar elementos interactivos como pop-ups.
m = folium.Map(location=[4.5709, -74.2973], zoom_start=6)
folium.Choropleth(
geo_data=mapa,
name='choropleth',
data=mapa,
columns=['DEPARTAMENTO', 'PROMEDIO'],
key_on='feature.properties.DEPARTAMENTO',
fill_color='plasma_r',
fill_opacity=0.5,
line_opacity=0.7,
legend_name='Precio Promedio',
highlight=True
).add_to(m)
for _, row in mapa.iterrows():
folium.Popup(f"{row['DEPARTAMENTO']}: {row['PROMEDIO']:.2f}").add_to(
folium.GeoJson(row['geometry'], name=row['DEPARTAMENTO'])
)
folium.LayerControl().add_to(m)
m